#include "cudacommon.h"
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <vector>

#include <thrust/functional.h>
#include <thrust/random.h>

using namespace std;

struct bitmask_plain : public thrust::unary_function<long,int>
{    
	int shift;
	bitmask_plain(int _shift) : shift(_shift) {}
	__host__ __device__
    int operator()(long a) const
    {
        return ((a >> shift) & 0xFFFF);
    }
};


// This functor implements a constant modulus operation
struct modulo_functor : public thrust::unary_function<long,long>
{
    long mod_factor;
    
    modulo_functor(long _mod_factor) : mod_factor(_mod_factor) {}

    __host__ __device__
    long operator()(long a) const
    {
        return a % mod_factor;
    }
};

// This functor calculates the destination rank based on global idx
struct rank_calc_functor : public thrust::unary_function<long long int, int>
{
    // Number of elems per rank
    long long int size_factor;
    
    rank_calc_functor(int _size_factor) : size_factor(_size_factor) {}

    __host__ __device__
    int operator()(long long int a) const
    {
        return (int)(a / size_factor);
    }
};

struct uniform_rand //: public thrust::unary_function<int,int>
{
    __host__ __device__
    long operator()(int in)
    {
        // Uniform random initialization
        thrust::default_random_engine rng;
        thrust::uniform_real_distribution<long> uniform_dist(0, LONG_MAX);
        return uniform_dist(rng);
    }
};

struct normal_rand //: public thrust::unary_function<int,int>
{
    __host__ __device__
    long operator()(int in)
    {
        // Random initialization - Gaussian
        thrust::minstd_rand rng;
        thrust::random::experimental::normal_distribution<double> dist(INT_MAX, 2 << 8);
        return (long)(dist(rng));
    }
};
